#!/usr/bin/env python

import os
import shutil
import hashlib
import component
import sqlalchemy as sa

import sqlalchemy.orm as sao

import _base as base

from datetime import datetime
from model import DeclarativeBase

__all__ = ['Post']

class Post(DeclarativeBase):
    """Post class"""
    
    STATUS_QUEUED = 'queued'
    STATUS_DOWNLOADED = 'downloaded'
    # archived means downloaded but the file is not avaiable for viewing
    STATUS_ARCHIVED = 'archived'
    # the image didn't meet standard
    STATUS_DELETED = 'deleted'
    
    __tablename__ = 'posts'
    
    id = sa.Column(sa.Integer, primary_key=True)
    md5 = sa.Column(sa.String(32), nullable=False, unique=True, index=True)
    status = sa.Column(sa.String(16), index=True)
    extension = sa.Column(sa.String(4))
    size = sa.Column(sa.Integer)
    tag = sa.Column(sa.Text)
    createdAt = sa.Column(sa.DateTime, default=datetime.now)
    updatedAt = sa.Column(sa.DateTime, default=datetime.now,
                          onupdate=datetime.now)
    boorus = sao.relationship('Booru', backref='posts')
    
    _str = None
    
    def __str__(self):
        """A string representation of Post"""
        
        if self._str: return self._str
        
        infos = []
        
        if self.file.image:
            infos.append('Dimension: %s x %s pixels.' % self.file.image.size)
        infos.append('Size: %s' % component.Formatter.byte(self.size))
        infos.append('MD5: %s' % self.md5)
        infos.append('Type: %s' % self.extension)
        infos.append('Tags: %s' % self.tag.strip())
        infos.append('')
        
        for booru in self.boorus:
            infos.append('%s:' % booru.host.name)
            infos.append('    ID: {:,}'.format(booru.originalId))
            format = '%A, %B %d, %Y %I:%M:%S %p'
            infos.append('    Uploaded: %s' % booru.dateTime.strftime(format))
            
        self._str = '\n'.join(infos)
        
        return self._str
    
    @property
    def tags(self):
        """A set of tag"""
        
        tags = [x.strip() for x in self.tag.strip().split(' ')]
        return sorted(set(tags) - set(['']))
    
    @property
    def filename(self):
        """A string of filename as md5.extension"""
        
        return '%s.%s' % (self.md5, self.extension)
    
    @property
    def humanFilename(self):
        """A string of filename as tag.extension"""
        
        return '%s.%s' % (self.tag.strip(), self.extension)
    
    _file = None
    
    @property
    def file(self):
        """A File instance of post"""
        
        if self._file: return self._file
    
        self._file = component.File(os.path.join('image', self.filename))
        
        return self._file
    
    _temp = None
    
    @property
    def temp(self):
        """A File instance of temporary post"""
        
        if self._temp: return self._temp
        
        self._temp = component.File(os.path.join('temp', self.filename))
        
        return self._temp
    
    def trash(self):
        """Set status to deleted and delete the file.
        
        Returns:
            Boolean indicating operation succeed. When operation fails, that
            because somehow python could not unlink the file.
        """
        
        self.status = self.STATUS_DELETED
        return self.file.unlink()
        
    def queue(self):
        """Set status to queued.
        
        Returns:
            Boolean.
        """
        
        self.status = self.STATUS_QUEUED
        return True
    
    def download(self):
        """Set status to downloaded.
        
        Returns:
            Boolean.
        """
        
        self.status = self.STATUS_DOWNLOADED
        return True
    
    def export(self, path, useMd5=False):
        """Save file to path.
        
        If useMd5 is false, will save as tag.extension, otherwise md5.extension
        and md5.txt which contains the tag.
        
        Args:
            path: A valid directory path.
            useMd5: Save file as md5.extension with text file containing the
                tag.
            
        Raises:
            See shutil.copy error exception.
        """
        
        path = path if os.path.isabs(path) else os.path.abspath(path)
        dest = os.path.join(path, self.humanFilename)
        if useMd5:
            dest = os.path.join(path, self.filename)
            
            md5Filename = '%s.txt' % self.md5
            tagFile = open(os.path.join(path, md5Filename), 'w')
            tagFile.write('\n'.join(self.tags))
            tagFile.close()
        
        shutil.copy(self.file.absPath, dest)
        